#pragma once
#include "object_base.h"
#include "object_traits.h"
#include <list>

namespace Pdf
{
    template <ObjectType Type>
    class __declspec(novtable) SimpleObjectT : public Object
    {
    public:
        typedef SmartPtr<SimpleObjectT>                Ptr;
        typedef typename ObjectTraitsT<Type>::Value    Value;

                SimpleObjectT() throw();
                SimpleObjectT(const Value &src);

        Value   get() const throw();
        void    set(const Value &src);

    protected:
        Value   value;
    };

    // =====================================================================

    template <ObjectType Type>
    class __declspec(novtable) ContainerObjectT : public Object
    {
    public:
        typedef SmartPtr<ContainerObjectT>              Ptr;
        typedef typename ObjectTraitsT<Type>::Value     Value;
        typedef typename ObjectTraitsT<Type>::Index     Index;
        typedef typename Value::iterator                Iterator;
        typedef typename Value::size_type               SizeType;

                        ContainerObjectT() throw();
						ContainerObjectT(const Value &value);
                        ContainerObjectT(const std::list<Object::Ptr> &src);

        Object::Ptr     get(const Index &idx) throw();
        void            set(const Index &idx, Object::Ptr src);
        SizeType        count() const throw();
        Iterator        begin() throw();
        Iterator        end() throw();

        template <typename TargetType>
        typename TargetType::Ptr get(const Index &idx);

    protected:
        static void __fastcall init(ContainerObjectT *obj, const std::list<Object::Ptr> &src);

        Value           value;
    };

    // =====================================================================

    template <typename ObjectType>
    struct VisitableT : public ObjectType
    {
        VisitableT() throw();

        template <typename Arg1>
        VisitableT(const Arg1 &arg1);

        template <typename Arg1, typename Arg2>
        VisitableT(const Arg1 &arg1, const Arg2 &arg2);

        virtual void        __fastcall apply(Visitor *visitor);
		virtual VisitableT* __fastcall clone();
    };

    // =====================================================================

    typedef VisitableT< SimpleObjectT<objNull> >            Null;
    typedef VisitableT< SimpleObjectT<objInteger> >         Integer;
    typedef VisitableT< SimpleObjectT<objReal> >            Real;
    typedef VisitableT< SimpleObjectT<objKeyword> >         Keyword;
    typedef VisitableT< SimpleObjectT<objComment> >         Comment;
    typedef VisitableT< SimpleObjectT<objName> >            Name;
    typedef VisitableT< SimpleObjectT<objString> >          String;
    typedef VisitableT< SimpleObjectT<objReference> >       Reference;
    typedef VisitableT< ContainerObjectT<objArray> >        Array;
    typedef VisitableT< ContainerObjectT<objNames> >        Names;
    typedef VisitableT< ContainerObjectT<objDictionary> >   Dictionary;

    // =====================================================================

    struct __declspec(novtable) Visitor
    {
        virtual void __fastcall visited(Null *obj) = 0;
        virtual void __fastcall visited(Integer *obj) = 0;
        virtual void __fastcall visited(Real *obj) = 0;
        virtual void __fastcall visited(Keyword *obj) = 0;
        virtual void __fastcall visited(Comment *obj) = 0;
        virtual void __fastcall visited(Name *obj) = 0;
        virtual void __fastcall visited(String *obj) = 0;
        virtual void __fastcall visited(Array *obj) = 0;
        virtual void __fastcall visited(Names *obj) = 0;
        virtual void __fastcall visited(Dictionary *obj) = 0;
        virtual void __fastcall visited(Reference *obj) = 0;
    };

    template <typename DefaultPolicy>
    class __declspec(novtable) VisitorT : public Visitor
    {
        virtual void __fastcall visited(Null *obj);
        virtual void __fastcall visited(Integer *obj);
        virtual void __fastcall visited(Real *obj);
        virtual void __fastcall visited(Keyword *obj);
        virtual void __fastcall visited(Comment *obj);
        virtual void __fastcall visited(Name *obj);
        virtual void __fastcall visited(String *obj);
        virtual void __fastcall visited(Array *obj);
        virtual void __fastcall visited(Names *obj);
        virtual void __fastcall visited(Dictionary *obj);
        virtual void __fastcall visited(Reference *obj);
    };

    struct DefaultNone
    {
        template <typename TargetType>
        static void __fastcall visited(TargetType *obj) throw();
    };

    struct DefaultError
    {
        template <typename TargetType>
        static void __fastcall visited(TargetType *obj);
    };
}

#include "object.inl"